package com.swizipuremvc.core.utils
{
	import flash.utils.Dictionary;
	import flash.utils.describeType;

	public class InjectionManager
	{
		private var _injectableMapping:Dictionary = new Dictionary();

		public function InjectionManager()
		{
			registerInjectable("injectionManager", this);
		}

		public function registerInjectable(id:String, object:*):void
		{
			_injectableMapping[id] = { "object": object, "initialized": false };
		}

		public function addAlias(alias:String, id:String):void
		{
			var obj:Object = _injectableMapping[id];
			if (obj)
			{
				_injectableMapping[alias] = obj;
			}
			else
			{
				throw new Error("Injectble with id " + id + " not found for alias " + alias);
			}
		}

		public function processInjection(object:Object):void
		{
			for each (var acc:XML in describeType(object)..accessor)
			{
				if ((acc.@access == "writeonly") || (acc.@access == "readwrite"))
				{
					for each (var meta:XML in acc..metadata)
					{
						if (meta.@name == "Inject")
						{
							var metaArgs:Object = new Object();
							for each (var arg:XML in meta..arg)
							{
								metaArgs[arg.@key] = arg.@value;
							}
							var id:String = metaArgs['id'];
							if (!id)
							{
								id = String(acc.@name);
							}
							if (!_injectableMapping[id])
							{
								throw new Error('Injectable resource with id "' + id + '" not found! while injecting to ' + object);
							}
							if (metaArgs['scope'] == 'prototype')
							{
								var factory:* = _injectableMapping[id].object;
								var bean:Object;
								if (factory is Class)
								{
									bean = new factory()
								}
								else if (factory is Function)
								{
									bean = factory();
								}
								else
								{
									throw new Error('Could not determine factory of "' + factory + '" for resource "' + id + '"! while injecting to ' + object);
								}
								processInjection(bean);
								object[acc.@name] = bean;
							}
							else
							{
								if (!_injectableMapping[id].initialized)
								{
									_injectableMapping[id].initialized = true;
									processInjection(_injectableMapping[id].object);
								}
								object[acc.@name] = _injectableMapping[id].object;
							}
						}
					}
				}
			}
		}
	}
}
